package cpe.hapa;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.simple.JSONObject;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.appengine.labs.repackaged.org.json.JSONArray;

import cpe.hapa.authentication.Authenticate;
import cpe.hapa.dao.DatacacheSingleton;
import cpe.hapa.dao.VolDAO;
import cpe.hapa.dao.SearchDAO;
import cpe.hapa.model.User;
import cpe.hapa.model.Vol;

/**
 * Servlet implementation class VolServlet
 */

public class VolServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public VolServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		switch(request.getParameter("cmd")) {
			case "listeVol" :
				listeVol(request,response);
				break;
			case "listeVolHistoric" :
				listeVolHistoric(request,response);
				break;
			case "listeSearch":
				listeSearch(request,response);
				break;
			default:
				throw new ServletException("Cette commande n'existe pas");
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		switch(request.getParameter("cmd")) {
			case "addVol" :
				addVol(request, response);
				break;
			case "addVolQueue" :
				addVolQueue(request,response);
				break;
			case "searchVol" :
				searchVol(request,response);
				break;
			default:
				throw new ServletException("Cette commande n'existe pas");
		}
	}

	

	@Override
	protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
		switch(req.getParameter("cmd")) {
		case "deleteVol" :
			DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
			Key deleteKey = KeyFactory.stringToKey(req.getParameter("id"));
			datastore.delete(deleteKey);
			break;
		case "deleteVolQueue" :
			Queue queue = QueueFactory.getDefaultQueue();
			TaskOptions task = TaskOptions.Builder.withUrl("/vol?cmd=deleteVol&id=" + req.getParameter("id")).method(Method.DELETE);
			queue.add(task);
			break;
		default:
			throw new ServletException("Cette commande n'existe pas");
		}
	}
	
	@Override
	protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		switch(req.getParameter("cmd")){
		case "updateSearch" :
			try {
				SearchDAO.updateSearch(KeyFactory.stringToKey(req.getParameter("id")));
			} catch (EntityNotFoundException | CacheException e) {
				e.printStackTrace();
			}
			resp.getWriter().print("{\"redirect\":\"volSearch.html\"}");
			break;
		case "updateVol" :
			break;
		default:
			throw new ServletException("Cette commande n'existe pas");
		}
	}

	/********************************
	 * =============================
	 * COMMANDES ET SOUS-METHODES
	 * =============================
	 *********************************/
	private void addVol(HttpServletRequest request, HttpServletResponse response) throws ServletException {
		String leavingFrom = request.getParameter("leavingFrom");
		String goingTo = request.getParameter("goingTo");
		String departureDate = request.getParameter("departureDate");
		String arrivalDate = request.getParameter("arrivalDate");
		String departureTime = request.getParameter("departureTime");
		String arrivalTime = request.getParameter("arrivalTime");
		String price = request.getParameter("price");
		String availableSeats = request.getParameter("availableSeats");
		User connectedUser = null;
		Vol vol = null;
		
		try {
			connectedUser = Authenticate.getConnectedUser(request);
		} catch (NumberFormatException | ParseException e) {
			throw new ServletException(e);
		}
		
		//if( (connectedUser != null && connectedUser.isInRole(RoleDAO.getAdminRole()))) {
		//}
		
		try {
			vol = this.checkAndInstantiateVolModel(leavingFrom, goingTo, departureDate, arrivalDate, departureTime, arrivalTime, price, availableSeats);
		} catch(ParseException e) {
			throw new ServletException(e);
		}
		
		if (vol != null) {
			VolDAO.addVol(vol);
		} else {
			throw new ServletException("Données du formulaire incorrectes");
		}		
	}
	
	
	private void listeSearch(HttpServletRequest request,HttpServletResponse response) throws IOException {
		try {
			PreparedQuery researchPreparedQuery = SearchDAO.getHistoric(request);
		
			JSONArray searchList = new JSONArray();
			for(Entity result : researchPreparedQuery.asIterable())
			{				
				JSONObject search = new JSONObject();
				search.put("id", KeyFactory.keyToString(result.getKey()));
				search.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(result.getProperty("date")));
				search.put("leavingFrom", result.getProperty("leavingFrom"));
				search.put("goingTo", result.getProperty("goingTo"));
				search.put("departure", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(result.getProperty("departure")));
				search.put("responseCount", result.getProperty("responseCount"));
				searchList.put(search);
			}
			response.getWriter().print(searchList);
		} catch (NumberFormatException | ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void listeVolHistoric(HttpServletRequest request,HttpServletResponse response) throws IOException {
		try {
			Cache cache = DatacacheSingleton.getInstance();
		
			PreparedQuery preparedHistoricQuery = VolDAO.getSearchVol((String)cache.get("leavingFrom"),(String)cache.get("goingTo"),(Date)cache.get("departure")); 
			JSONObject search = new JSONObject();
			search.put("leaving", (String)cache.get("leavingFrom"));
			search.put("going", (String)cache.get("goingTo"));
			search.put("time", new SimpleDateFormat("HH:mm").format((Date)cache.get("departure")));
			search.put("date", new SimpleDateFormat("yyyy-MM-dd").format((Date)cache.get("departure")));
			cache.clear();
			JSONArray volHistoricList = new JSONArray();
			volHistoricList.put(search);
			for(Entity result : preparedHistoricQuery.asIterable())
			{				
				JSONObject vol = new JSONObject();
				vol.put("id", KeyFactory.keyToString(result.getKey()));
				vol.put("departureDate", result.getProperty("departureDate"));
				vol.put("departureTime", result.getProperty("departureTime"));
				vol.put("arrivalDate", result.getProperty("arrivalDate"));
				vol.put("arrivalTime", result.getProperty("arrivalTime"));
				vol.put("duration", result.getProperty("duration"));
				vol.put("price", result.getProperty("price"));
				vol.put("availableSeats", result.getProperty("availableSeats"));
				volHistoricList.put(vol);
			}
			
			response.getWriter().print(volHistoricList);
		} catch (CacheException | NullPointerException e) {
			response.getWriter().print("{\"message\":\"No Cache\"}");
		}
	}

	private void listeVol(HttpServletRequest request,HttpServletResponse response) throws IOException {
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query volListQuery = new Query("Vol")
		.addSort("departureDate", SortDirection.ASCENDING)
		.addSort("departureTime", SortDirection.ASCENDING);
		
		PreparedQuery preparedQuery = datastore.prepare(volListQuery);
		
		JSONArray volList = new JSONArray();
		for(Entity result : preparedQuery.asIterable())
		{
			Date flightDate = new Date();
			try {
				flightDate = (Date) new SimpleDateFormat("yyyy-MM-dd").parse(result.getProperty("departureDate").toString());
			} catch (ParseException e1) {
				flightDate = new Date();
				e1.printStackTrace();
			}
			
			JSONObject vol = new JSONObject();
			vol.put("id", KeyFactory.keyToString(result.getKey()));
			vol.put("date", new SimpleDateFormat("yyyy-MM-dd").format(flightDate));
			vol.put("leavingFrom", result.getProperty("leavingFrom"));
			vol.put("goingTo", result.getProperty("goingTo"));
			vol.put("flightDuration", result.getProperty("duration"));
			vol.put("price", result.getProperty("price"));
			vol.put("availableSeats", result.getProperty("availableSeats"));
			volList.put(vol);
		}
		response.getWriter().print(volList);
	}
	
	private void searchVol(HttpServletRequest request,HttpServletResponse response) throws IOException {
		Date departure;
		try {
			String s = request.getParameter("departureDate");
			
			departure = new SimpleDateFormat("yyyy-MM-dd").parse(request.getParameter("departureDate"));
			Calendar cal = Calendar.getInstance();
			cal.setTime(departure);
			cal.add(Calendar.HOUR, Integer.parseInt(request.getParameter("departureTime").toString().split(":")[0]));
			cal.add(Calendar.MINUTE, Integer.parseInt(request.getParameter("departureTime").toString().split(":")[1]));
			
			departure = cal.getTime();
			
		} catch (ParseException e) {
			departure = new Date();
		};
		
		PreparedQuery preparedQuery = VolDAO.getSearchVol(request.getParameter("leavingFrom"),request.getParameter("goingTo"),departure); 
		
		int responseCount = 0;
		JSONArray volList = new JSONArray();
		
		for(Entity result : preparedQuery.asIterable())
		{				
			JSONObject vol = new JSONObject();
			vol.put("id", KeyFactory.keyToString(result.getKey()));
			vol.put("departureDate", result.getProperty("departureDate"));
			vol.put("departureTime", result.getProperty("departureTime"));
			vol.put("arrivalDate", result.getProperty("arrivalDate"));
			vol.put("arrivalTime", result.getProperty("arrivalTime"));
			vol.put("duration", result.getProperty("duration"));
			vol.put("price", result.getProperty("price"));
			vol.put("availableSeats", result.getProperty("availableSeats"));
			volList.put(vol);
			responseCount++;
		}

		try {
			SearchDAO.addSearch(request.getParameter("leavingFrom"),request.getParameter("goingTo"),departure,responseCount,KeyFactory.keyToString(Authenticate.getConnectedUser(request).getKey()));
		} catch (NumberFormatException | ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		response.getWriter().print(volList);
	}

	private void addVolQueue(HttpServletRequest request,HttpServletResponse response) {
		Queue queue = QueueFactory.getDefaultQueue();
		TaskOptions task=TaskOptions.Builder.withUrl("/vol")
				.param("cmd", "addVol")
				.param("leavingFrom", request.getParameter("leavingFrom"))
				.param("goingTo", request.getParameter("goingTo"))
				.param("departureDate", request.getParameter("departureDate"))
				.param("arrivalDate", request.getParameter("arrivalDate"))
				.param("departureTime", request.getParameter("departureTime"))
				.param("arrivalTime", request.getParameter("arrivalTime"))
				.param("price", request.getParameter("price"))
				.param("availableSeats", request.getParameter("availableSeats"));
		queue.add(task);
	}

	private Vol checkAndInstantiateVolModel(String leavingFrom, String goingTo,
			String departureDate, String arrivalDate,
			String departureTime, String arrivalTime, String price,
			String availableSeats) throws ParseException {
		Vol vol = null;
		if ( leavingFrom != null && 
				goingTo != null && 
				departureDate != null &&
				departureTime != null && 
				arrivalDate != null &&  
				arrivalTime != null && 
				price != null && 
				availableSeats != null &&
				!leavingFrom.isEmpty() && 
				!goingTo.isEmpty() && 
				!departureDate.isEmpty() &&
				!departureTime.isEmpty() && 
				!arrivalDate.isEmpty() && 
				!arrivalTime.isEmpty() && 
				!price.isEmpty() && 
				!availableSeats.isEmpty())
		{
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			vol = new Vol(
				leavingFrom,
				goingTo, 
				sdf.parse(departureDate),
				sdf.parse(arrivalDate),
				departureTime, 
				arrivalTime,
				Double.valueOf(price),
				Integer.valueOf(availableSeats)
			);
			
		}
		return vol;
	}
}
